<template>
  <!-- 使用v-show控制面板显隐 -->
  <div class="panel right-panel" :style="{
    width: width + 'px'
    // ,minWidth: '200px',maxWidth: '350px'
  }" v-show="true">
    <!-- 聊天消息区 -->
    <div class="ai-header">AI助手</div>

    <div class="ai-chat">
      <div class="chat-message-wrapper" v-for="msg in chatMessages" :key="msg.id">

        <div :class="['chat-message', 'message-' + msg.type]">
          <strong>{{ msg.type === 'user' ? '你' : 'AI' }}：</strong>
          <!--          <pre class="message-content" v-html="formatMessage(msg.content)"></pre>-->
          <pre class="message-content">{{ msg.content }}</pre>
        </div>
      </div>
      <!--    有问题提示位置  -->
      <div v-if="streamError" class="stream-error-message">
        {{ streamError }}
      </div>
    </div>


    <div class="panel-content">
      <div class="ai-input">
        <div class="input-group">
          <el-select v-model="modelSel" placeholder="模型切换" size="small"
                     class="custom-change-btn">
            <el-option label="DeepSeek" value="deepseek-ai/DeepSeek-V3"
                       :key="'deepseek-ai/DeepSeek-V3'"></el-option>
            <el-option label="通义千问" value="Qwen/Qwen3-8B" :key="'Qwen/Qwen3-8B'"></el-option>
          </el-select>
          <el-input v-model="chatInput" placeholder="输入问题..." clearable ref="inputRef" class="custom-input"
            @keyup.enter="isStreaming ? null : toggleStream()" :disabled="isStreaming" />
          <button @click="toggleStream" class="stream-action-button" :class="{ 'streaming': isStreaming }"
            :title="isStreaming ? '停止对话' : '发送消息'" ref="streamButtonRef">
            <span v-if="!isStreaming">
              <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
                <path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"></path>
              </svg>
            </span>
            <span v-else>
              <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
                <path d="M6 18h12V6H6v12zM8 8h8v8H8V8z"></path>
              </svg>
            </span>
          </button>
        </div>
      </div>
      <!--      <p>固定宽度: {{ width }}px</p>-->
    </div>
  </div>
</template>


<script setup lang="ts">
import {ref, onMounted, nextTick, watch, onUnmounted} from 'vue';
import {currentNodeInfo} from '@/stores/currentNodeStore';
import { aiMessageStore } from '@/stores/aiMessage';
const aiMmgStore = aiMessageStore()
const currentNode = currentNodeInfo()

interface ChatMessage {
  id: string; /*消息唯一标识*/
  type: 'user' | 'ai';
  content: string; /*消息文本内容*/
}

/*通过props从父组件接收以下参数*/
const props = defineProps({
  width: {
    type: Number,
    required: true
  },
  visible: {
    type: Boolean,
    required: true
  },
  initialMessages: {
    type: Array as () => string[],
    default: () => []
  }
});

const emit = defineEmits(['close', 'update:isAIOpen', 'messageSent', 'modelChanged']);


const chatInput = ref('');/* 用户输入框内容 */
const inputRef = ref<any>(null);
const streamButtonRef = ref<HTMLButtonElement | null>(null);
const modelSel = ref('deepseek-ai/DeepSeek-V3');/* 当前选择的AI模型 */
const isStreaming = ref(false);
const streamError = ref<string | null>(null);
const abortController = ref<AbortController | null>(null);/* 中断控制器 */
let currentAiMessageId: string | null = null;/* 当前AI消息ID */


/* 识别消息类型，添加前缀 */
const parseInitialMessage = (msgStr: string): { type: 'user' | 'ai', content: string } => {
  const lowerMsgStr = msgStr.toLowerCase();

  let type: 'user' | 'ai' = 'ai';
  let content = msgStr.trim();

  const userPrefixes = ["你：", "user:"];
  const aiPrefixes = ["ai：", "assistant:"];

  for (const prefix of userPrefixes) {
    if (lowerMsgStr.startsWith(prefix)) {
      type = 'user';
      content = msgStr.substring(prefix.length).trim();
      break;
    }
  }
  if (type === 'ai') {
    for (const prefix of aiPrefixes) {
      if (lowerMsgStr.startsWith(prefix)) {
        type = 'ai';
        content = msgStr.substring(prefix.length).trim();
        break;
      }
    }
  }
  return {type, content};
};


/* 初始化聊天消息列表  */
const chatMessages = ref<ChatMessage[]>(
  /* 父组件传递过来的初始消息数组 */
  props.initialMessages.map((msgStr, index) => {
    const {type, content} = parseInitialMessage(msgStr);
    return {id: `initial-${index}-${Date.now()}`, type, content};
  })
);

/* 自动滚动到最下面 */
const scrollToBottom = () => {
  /* 确保在 Vue 完成 DOM 更新后执行滚动操作 */
  nextTick(() => {
    /* 获取聊天区域对应的元素（class=ai-chat） */
    const chatArea = document.querySelector('.ai-chat');
    if (chatArea) {
      /* scrollHeight是元素的高度，设置后，就会跟改到追下面 */
      chatArea.scrollTop = chatArea.scrollHeight;
    }
  });
};


/* 同步输入框和按钮高度 */
const syncInputButtonHeight = () => {
  /* 确保在 Vue 完成 DOM 更新后执行高度同步操作 */
  nextTick(() => {
    /* 检查输入和按钮是否存在 */
    if (inputRef.value && inputRef.value.$el && streamButtonRef.value) {
      const inputEl = inputRef.value.$el.querySelector('.el-input__inner') as HTMLElement;
      const btnEl = streamButtonRef.value;
      if (inputEl && btnEl) {
        btnEl.style.height = `${inputEl.offsetHeight}px`;
      }
    }
  });
};

/*流式更新AI消息内容*/
const updateAiMessageWithStreamData = (data: string) => {
  const aiMessageEntry = chatMessages.value.find(m => m.id === currentAiMessageId);
  if (aiMessageEntry) {

    const formattedData = data.replace(/\\n/g, '\n');
    aiMessageEntry.content += formattedData;
    //存储ai回复消息
    aiMmgStore.resposeMarkdon = aiMessageEntry.content
    scrollToBottom();
  }
};





/* 更新最终消息状态(错误还是完成) */
const updateFinalAiMessageWithStatus = (statusMessage: string, isErrorType: boolean) => {
  const aiMessageEntry = chatMessages.value.find(m => m.id === currentAiMessageId);
  const messageToDisplay = `${isErrorType ? '[错误: ' : '['}${statusMessage}${isErrorType ? ']' : ']'}`;

  if (aiMessageEntry) {
    if (aiMessageEntry.content === '' || !aiMessageEntry.content.includes(messageToDisplay)) {
      aiMessageEntry.content += (aiMessageEntry.content.endsWith('\n') || aiMessageEntry.content === '' ? '' : '\n') + messageToDisplay;
    }
  } else if (currentAiMessageId) {
    chatMessages.value.push({id: currentAiMessageId, type: 'ai', content: messageToDisplay});
  } else {
    chatMessages.value.push({id: `ai-status-${Date.now()}`, type: 'ai', content: messageToDisplay});
  }
  scrollToBottom();
};


const startStream = async () => {
  const currentcontent = currentNode.nodeMarkdown;
  console.log(currentcontent);

  const userInput = chatInput.value.trim();
  /* 验证是否输入 */
  if (!userInput) {
    streamError.value = '请输入您的问题。';
    console.warn(streamError.value);
    return;
  }
  /* 设置状态 */
  isStreaming.value = true;
  streamError.value = null;
  abortController.value = new AbortController();
  /* 添加用户消息 */
  chatMessages.value.push({id: `user-${Date.now()}`, type: 'user', content: userInput});
  emit('messageSent', userInput);

  /* 创建AI的消息框把位置占住 */
  currentAiMessageId = `ai-${Date.now()}`;
  chatMessages.value.push({id: currentAiMessageId, type: 'ai', content: ''});
  chatInput.value = '';
  scrollToBottom();

  let doneReadingStream = false;

  /* 发起API请求 */
  try {
    const streamUrl = `http://localhost:8080/api/chat_t/stream_t`;

    // 添加调试日志
    console.log('尝试连接到:', streamUrl);
    console.log('请求数据:', {
      message: currentcontent + userInput,
      model: modelSel.value
    });


    const response = await fetch(streamUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        /* 声明接受事件流 */
        'Accept': 'text/event-stream',
        'satoken': localStorage.getItem("satoken")||""
      },
      body: JSON.stringify({
        message: currentcontent + userInput,
        model: modelSel.value,
      }),
      /* 绑定中断控制器 */
      signal: abortController.value.signal,
    });
    /* 检查HTTP是成功 */
    if (!response.ok) {
      let errorData = `请求失败，状态码: ${response.status}`;
      try {
        const errorJson = await response.json();
        errorData = errorJson.detail || errorJson.message || JSON.stringify(errorJson);
      } catch (e) {
        errorData = (await response.text()) || errorData;
      }
      throw new Error(errorData);
    }
    /* 检查响应体是否存在 */
    if (!response.body) {
      throw new Error('Response body is null. Streaming not possible.');
    }

    /* 创建读取流的 */
    const reader = response.body.getReader();
    /* 创建utf-8解码器 */
    const decoder = new TextDecoder('utf-8');
    /* 临时存储尚未处理数据 */
    let accumulatedChunk = '';

    //初始化ai

    while (!doneReadingStream) {
      try {
        const {value, done} = await reader.read();
        /* 处理数据块 */
        if (value) {
          accumulatedChunk += decoder.decode(value, {stream: true});
          /* 所有消息 */
          let contentForThisPass = "";

          const doneSignalIndex = accumulatedChunk.indexOf("[DONE]");
          if (doneSignalIndex !== -1) {
            const partBeforeDone = accumulatedChunk.substring(0, doneSignalIndex);
            partBeforeDone.split('\n').forEach(line => {
              const trimmedLine = line.trim();
              if (trimmedLine.startsWith("data:")) {
                contentForThisPass += trimmedLine.substring(5);

              }
            });
            accumulatedChunk = '';
            doneReadingStream = true;
          } else {
            let searchStartIndex = 0;
            while (true) {
              const newlineIndex = accumulatedChunk.indexOf('\n', searchStartIndex);
              if (newlineIndex === -1) break;

              const line = accumulatedChunk.substring(searchStartIndex, newlineIndex).trim();
              if (line.startsWith("data:")) {
                contentForThisPass += line.substring(5);
              }
              searchStartIndex = newlineIndex + 1;
            }
            accumulatedChunk = accumulatedChunk.substring(searchStartIndex);
          }

          if (contentForThisPass) {
            updateAiMessageWithStreamData(contentForThisPass);
          }
        }

        if (done) {
          doneReadingStream = true;
        }

        if (doneReadingStream) {

          if (accumulatedChunk.trim()) {
            let finalContent = "";

            const linesInFinal = accumulatedChunk.split('\n');
            for (const line of linesInFinal) {
              const trimmedLineFinal = line.trim();
              if (trimmedLineFinal.startsWith("data:")) {
                finalContent += trimmedLineFinal.substring(5);
              }
            }
            if (finalContent) {
              updateAiMessageWithStreamData(finalContent);
            }
            accumulatedChunk = '';
          }
          break;
        }
        /* 错误处理 */
      } catch (readError: any) {
        if (readError.name === 'AbortError') {
          console.log('Stream reading aborted.');

          if (!streamError.value) streamError.value = '数据流读取中止';
        } else {
          console.error('Error reading stream chunk:', readError);
          streamError.value = `读取数据流时发生错误: ${readError.message}`;
        }
        doneReadingStream = true;
        break;
      }
    }
    // console.log("==="+contentForThisPass)

    if (decoder.decode()) { /* final flush */
    }

  } catch (err: any) {
    if (err.name === 'AbortError') {

      if (!streamError.value) streamError.value = '请求已中止';
    } else {
      console.error('Error in startStream:', err);
      streamError.value = `连接或处理错误: ${err.message || '未知错误'}`;
    }
  } finally {
    const wasActuallyStreaming = isStreaming.value;
    isStreaming.value = false;

    if (abortController.value && !abortController.value.signal.aborted) {
      abortController.value.abort();
    }
    abortController.value = null;

    if (streamError.value && currentAiMessageId) {
      const isErrorMsg = streamError.value.includes('错误') ||
        streamError.value.includes('失败') ||
        (!streamError.value.includes('用户主动终止对话') && streamError.value.includes('中止'));
      updateFinalAiMessageWithStatus(streamError.value, isErrorMsg);
    } else if (streamError.value) {
      updateFinalAiMessageWithStatus(streamError.value, true);
    } else if (wasActuallyStreaming && !streamError.value && currentAiMessageId) {

    }
    scrollToBottom();
  }
};


const stopStreamUserAction = () => {
  if (isStreaming.value) {
    streamError.value = '用户主动终止对话';
    if (abortController.value) {
      abortController.value.abort();
    }
  } else {
    isStreaming.value = false;
    abortController.value = null;
  }
};

const toggleStream = () => {


  if (isStreaming.value) {
    stopStreamUserAction();
  } else {
    startStream();
  }
};


watch(modelSel, (newValue) => {
  emit('modelChanged', newValue);

});

watch(chatMessages, scrollToBottom, {deep: true});

onMounted(() => {
  syncInputButtonHeight();
  window.addEventListener('resize', syncInputButtonHeight);
});

onUnmounted(() => {
  window.removeEventListener('resize', syncInputButtonHeight);
  if (isStreaming.value || abortController.value) { // If unmounting while active
    streamError.value = streamError.value || '组件卸载，对话中止';
    if (abortController.value && !abortController.value.signal.aborted) {
      abortController.value.abort();
    }
    isStreaming.value = false;
    abortController.value = null;
    // Potentially update UI if a message was being streamed
    if (currentAiMessageId && streamError.value) {
      updateFinalAiMessageWithStatus(streamError.value, true)
    }
  }
});

const closePanel = () => {
  emit('close');
};
</script>


<style scoped>
.panel {
  position: relative;
  background-color: #f0f2f5;
  border-left: 1px solid #dcdfe6;
  transition: width 0.3s ease;
  overflow: hidden;
  flex-shrink: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
}


.ai-header {
  padding: 15px;
  font-size: 16px;
  font-weight: bold;
  border-bottom: 1px solid #ddd;
  flex-shrink: 0;
}

.ai-chat {
  flex: 1;
  padding: 15px;
  overflow-y: auto;
  min-height: 0;
  background-color: #fff;
}

.chat-message-wrapper {
  margin-bottom: 10px;
}

.chat-message {
  padding: 8px 12px;
  border-radius: 6px;
  word-wrap: break-word;
  white-space: pre-wrap;
}

.message-user {
  background-color: #d1e7dd;
  text-align: right;
  margin-left: auto;
  max-width: 80%;
}

.message-user .message-content {
  text-align: left;
}


.message-ai {
  background-color: #f8f9fa;
  border: 1px solid #e9ecef;
  max-width: 80%;
}


.message-content {
  margin: 0;
  font-family: inherit;
  font-size: 0.95em;
  line-height: 1.6;
  white-space: pre-wrap !important;
  overflow-wrap: break-word;
  word-break: break-all;
}


.panel-content {
  flex-shrink: 0;
}

.ai-input {
  padding: 15px;
  border-top: 1px solid #ddd;
}

.input-group {
  display: flex;
  align-items: stretch;
}

.custom-change-btn {
  width: auto;
  min-width: 90px;
  margin-right: -1px;
}

.custom-change-btn .el-input__inner {
  border-radius: 4px 0 0 4px !important;
}


.custom-input {
  flex: 1;
}

.custom-input .el-input__inner {
  border-radius: 0 !important;
}


.stream-action-button {

  padding: 0 10px;
  background-color: #409eff;
  color: white;
  border: 1px solid #409eff;
  margin-left: -1px;
  cursor: pointer;
  display: flex;
  justify-content: center;
  align-items: center;
  transition: background-color 0.3s ease, transform 0.1s ease, border-color 0.3s ease;
  flex-shrink: 0;
  border-radius: 0 4px 4px 0;
}

.stream-action-button:hover {
  opacity: 0.9;
  background-color: #66b1ff;
  border-color: #66b1ff;
}

.stream-action-button:active {
  transform: scale(0.95);
}

.stream-action-button.streaming {
  background-color: #ff4d4f;
  border-color: #ff4d4f;
}

.stream-action-button.streaming:hover {
  background-color: #ff7875;
  border-color: #ff7875;
}


.stream-action-button svg {
  width: 18px;
  height: 18px;
}

.custom-input:focus-within {
  z-index: 1;
}

.stream-action-button:focus {
  z-index: 1;
}


.button-right-close {

  position: absolute;
  top: 10px;
  right: 15px;

  background-color: rgb(147, 187, 187);
  z-index: 10;
}

.stream-error-message {
  color: #ff4d4f;
  margin-top: 10px;
  padding: 8px;
  background-color: rgba(255, 77, 79, 0.1);
  border: 1px solid rgba(255, 77, 79, 0.3);
  border-radius: 4px;
  font-size: 0.9em;
}
</style>
